# 你想给某个实例attribute 增加除访问与修改之外的其他处理逻辑，比如类型检查或合法性验证。

class Person:
    def __init__(self, first_name):
        self.first_name = first_name

    @property
    def first_name(self):
        return self._first_name

    @first_name.setter
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Excepted a string')
        self._first_name = value

    @first_name.deleter
    def first_name(self):
        raise AttributeError("Can't delete attribute")

a = Person('Guido')
print(a.first_name)
try:
    a.first_name = 42
except Exception as e:
    print(e)

# 一个property 属性其实就是一系列相关绑定方法的集合。如果你去查看拥有property 的类，
# 就会发现property 本身的fget、fset 和fdel 属性就是类里面的普通方法。
print(Person.first_name.fget)
print(Person.first_name.fset)
print(Person.first_name.fdel)

# Properties 还是一种定义动态计算attribute 的方法。这种类型的attributes 并不会被实际的存储，而是在需要的时候计算出来
import math
class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return math.pi * self.radius ** 2

    @property
    def diameter(self):
        return self.radius * 2

    @property
    def perimeter(self):
        return 2 * math.pi * self.radius
c = Circle(4.0)
print(c.radius)
print(c.area)
print(c.diameter)
print(c.perimeter)
